/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pagrafo.genetico;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import pagrafo.controle.Controle;
import pagrafo.grafo.Grafo;
import pagrafo.util.Vetor;

/**
 *
 * @author Fabricio
 */
public class AlgoritmoGenetico {

    private Grafo g;
    /**
     * Vetor de cromossomos, no final o primeiro é o melhor cromossomo
     */
    private ArrayList<Cromossomo> cromossomos;
    private ArrayList<Cromossomo> cromossomosAux;
    /**
     * Número de Caminhões
     */
    private int k;
    /**
     * Capacidade máxima de cada caminhão
     */
    private double capacidade;
    /**
     * Controle
     */
    private Controle c;
    
    private int p;

    private int geracoes = 100;
    private Roteamento roteamento;

    /**
     * Inicia o algoritmo genético com a população incial zerada
     * @param g
     * @param k
     * @param capacidade
     * @param p
     * @param geracoes 
     */
    public AlgoritmoGenetico(Grafo g, int k, double capacidade, int p, int geracoes) {
        this.g = g;
        this.k = k;
        this.p = p;
        this.geracoes = geracoes;
        this.capacidade = capacidade;
        cromossomos = new ArrayList<Cromossomo>();
    }
    
    /**
     * Inicia o algoritmo genético a partir de alguns individos previamente selecionados
     * @param g
     * @param k
     * @param capacidade
     * @param p
     * @param geracoes
     * @param cromossomos 
     */
    public AlgoritmoGenetico(Grafo g, int k, double capacidade, int p, int geracoes, ArrayList<Cromossomo> cromossomos) {
        this.g = g;
        this.k = k;
        this.p = p;
        this.geracoes = geracoes;
        this.capacidade = capacidade;
        this.cromossomos = new ArrayList<Cromossomo>();
        this.cromossomos.addAll(cromossomos);
    }

    public double getCapacidade() {
        return capacidade;
    }

    public int getK() {
        return k;
    }

    public Roteamento getRoteamento() {
        return roteamento;
    }

    public Roteamento executar() {
        
        //População Inicial
        for (int i = 0; i < p; i++) {
            cromossomos.add(new Cromossomo(g, k, capacidade));
        }

        for (int i = 0; i < geracoes; i++) {
            Collections.sort(cromossomos);
            
            //System.out.println("Geração: " + i);
            //System.out.println("Média das Diferênças: " + Populacao.mediaDiferencaFitness(cromossomos));
            //System.out.println("Score do melhor cromossomo: " + cromossomos.get(0).getScore());
            
            this.cromossomosAux = new ArrayList<Cromossomo>();
            cromossomosAux.addAll(cromossomos);
            
            //Crossover
            this.cromossomosAux.addAll(Crossover.executar(cromossomos, (int) cromossomos.size()/2, g, k, capacidade));
            
            //Mutação
            for(int j = 0; j < (int)this.cromossomosAux.size()/2; j++){
                this.cromossomosAux.add(Mutacao.executar(this.cromossomosAux.get((int)Math.random()*this.cromossomosAux.size())));
            }
            
            //Tentativa de melhoramento do primeiro
            for(int j = 0; j < 10; j++){
                this.cromossomosAux.add(Mutacao.executar(this.cromossomos.get(0)));
            }
            
            /*Mutação em individos aleatórios da população
            for(int j = 0; j < 100; j++){
                this.cromossomosAux.add(Mutacao.mutacao(this.cromossomos.get(1+(int)Math.random()*this.cromossomos.size())));
            }*/
            
            /*int numMutacoes = (int)this.cromossomos.size()/8;
            for(int j = 0; j < numMutacoes; j++){
                this.cromossomosAux.add(Mutacao.mutacaoMelhorDeN(cromossomos.get(j),50 , 8));
            }*/
            
            cromossomos = SelecaoRoleta.selecionar(cromossomosAux, p);
        }
        
        Collections.sort(cromossomos);
        /*Populacao.imprimePopulacao(cromossomos);
        
        Cromossomo cMelhor = cromossomos.get(0);
        Cromossomo cUltimo = cromossomos.get(cromossomos.size() - 1);
        System.out.println("Fitnesse do melhor: " + cMelhor.getScore());
        System.out.println("Melhor roteamento: " + Cromossomo.imprimirCromossomo(cMelhor));

        System.out.println("Fitnesse do ultimo: " + cUltimo.getScore());
        System.out.println("Ultimo roteamento: " + Cromossomo.imprimirCromossomo(cUltimo));*/

        roteamento = new Roteamento(this.cromossomos.get(0));
        return roteamento;

    }

    public ArrayList<Cromossomo> getCromossomos() {
        return cromossomos;
    }
    
}
